use crate::token::{Token, TokenKind, Span};
pub struct Code {
    pub stmts: Vec<Stmt>,
}

#[derive(Debug, PartialEq)]
pub enum Stmt {
    ExprStmt(Expr),
    EOF,
}

impl Stmt {
    pub fn expr(expr: Expr) -> Self {
        Stmt::ExprStmt(expr)
    }
}

#[derive(Debug, PartialEq)]
pub enum Op {
    Add,
    Sub,
    Mul,
    Div,
}


#[derive(Debug, PartialEq)]
pub struct Expr {
    pub kind: ExprKind,
    pub span: Span,
}

#[derive(Debug, PartialEq)]
pub enum ExprKind {
    IntExpr(i32),
    FloatExpr(f64),
    BoolExpr(bool),
    StrExpr(String),
    BinaExpr(Op, Box<Expr>, Box<Expr>),
    EOF,
}

impl Expr {
    pub fn single(token: &Token) -> Self {
        match token.kind {
            TokenKind::Int(n) => Expr { kind: ExprKind::IntExpr(n), span: token.span },
            TokenKind::Float(f) => Expr { kind: ExprKind::FloatExpr(f), span: token.span },
            TokenKind::Bool(b) => Expr { kind: ExprKind::BoolExpr(b), span: token.span },
            TokenKind::Str => Expr { kind: ExprKind::StrExpr(token.text.clone()), span: token.span },
            _ => panic!("Expected integer token"),
        }
    }

    pub fn eof(token: &Token) -> Self {
        Expr { kind: ExprKind::EOF, span: token.span }
    }

    pub fn binary(op: Op, lhs: Expr, rhs: Expr) -> Self {
        let start = lhs.span.start;
        let end = rhs.span.end;
        Expr { kind: ExprKind::BinaExpr(op, Box::new(lhs), Box::new(rhs)), span: Span{start, end} }
    }

}

